#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
#include <time.h>
#include <sys/wait.h>
#include "task.hpp"

using namespace std;

enum
{
    Usage_err = 1,
    Numproce_err,
    Pipe_err
};

// 管理进程和对应的管道
class Channel
{
public:
    Channel(int wfd, pid_t id, const string &name)
        : _wfd(wfd), _subprocess_id(id), _name(name)
    {
    }

    void Print()//代码前期测试用的
    {
        cout << "wfd: " << _wfd;
        cout << " subprocess_id: " << _subprocess_id;
        cout << " name: " << _name << endl;
    }

    string getName() {return _name;}
    int getWfd() {return _wfd;}
    pid_t getPid() {return _subprocess_id;}

    void Close()
    {
        close(_wfd);
    }

    ~Channel()
    {
    }

private:
    int _wfd;
    pid_t _subprocess_id;
    string _name;
};

// 管理进程池
class ProcessPool
{
public:
    ProcessPool(int sub_process_num) : _sub_process_num(sub_process_num)
    {
    }

    int CreateProcesspool(work_t work)
    {
        for (int number = 0; number < _sub_process_num; number++)
        {
            //创建管道
            int pipefd[2]{0};
            int n = pipe(pipefd);
            if (n < 0)
                return Pipe_err;

            pid_t id = fork();
            if (id == 0)
            {
                // 子进程 - r
                close(pipefd[1]);
                // 子进程执行任务
                dup2(pipefd[0], 0);//重定向到管道
                work(pipefd[0]);
            
                exit(1); // 终止子进程
            }
            // 父进程 - w
            close(pipefd[0]);
            // 父进程给任务
            string cname = "thread-" + to_string(number);
            channels.push_back(Channel(pipefd[1], id, cname));//保存数据
        }
        return 1;
    }

    int ChanNext()
    {
        static int next = 0;
        int c = next;
        next++;
        next %= channels.size();
        return c;
    }

    void SendTaskCode(int index, uint32_t code)
    {
        cout << "send code: " << code << " to " << channels[index].getName() << 
        " sub process id: " << channels[index].getPid() << endl;
        write(channels[index].getWfd(), &code, sizeof(code));
    }

    void Dubug()
    {
        for (auto channel : channels)
        {
            channel.Print();
        }
    }

    void KillAll()
    {
        for(auto channel:channels)
        {
            channel.Close();
            cout << channel.getName() << "close done, sub process: " << channel.getPid() << endl; 
        }
    }
    void Wait()
    {
        for(auto channel:channels)
        {
            pid_t pid = channel.getPid();
            pid_t rid = waitpid(pid, nullptr, 0);
            if(rid == pid)
            {
                cout << "sub process: " << pid << " wait success!" <<endl;
            }
        }
    }

    ~ProcessPool()
    {
    }

private:
    int _sub_process_num;
    vector<Channel> channels;
};

void Usage(string proc)
{
    cout << "Usage: " << proc << "subprocess_num" << endl;
}
int main(int argc, char *argv[])
{
    if (argc != 2) // 格式
    {
        Usage(argv[0]);
        return Usage_err;
    }
    int sub_process_num = stoi(argv[1]); // 获取进程的个数
    if (sub_process_num <= 0)
        return Numproce_err;

    srand((uint64_t)time(nullptr));

    // 1、创建子进程和管道
    ProcessPool *process_ptr = new ProcessPool(sub_process_num);
    process_ptr->CreateProcesspool(worker);
    //process_ptr->Dubug();

    // 2、控制子进程
    int cnt = 6;
    while(cnt--)
    {
        //1、选择进程和管道
        int channel = process_ptr->ChanNext();
        //cout << channel.getName() << endl;
        
        //2、选择一个任务
        uint32_t code = NextTask();

        //3、发送任务
        process_ptr->SendTaskCode(channel, code);

        sleep(1);
    }
     
    // 3、回收资源
    //a.让所有子进程退出
    process_ptr->KillAll();
    //b.等待回收资源
    process_ptr->Wait();

    sleep(100);

    delete process_ptr;

    return 0;
}